﻿/********
* 
* 
*  Description:
*  Create By kain.hong at 8/9/2010 4:53:48 PM
*  
*
*  Revision History:
*  Date                  Who                 What
*  
* 
*/
#region namespace

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;
using Cherry.Agile.ServiceModel;
using Cherry.Agile.ServiceModel.Security;
using Cherry.Agile.Security;
using System.Diagnostics;


#endregion


namespace Cherry.Agile.ServiceModel.Interceptor {

    internal class ClientMessageInspector : IClientMessageInspector {
        /// <summary>
        /// 是否支持双向消息头存储
        /// </summary>
        public bool IsBidirectional { get; set; }

        public PolicyLevel PolicyLevel { get; set; }
        public ClientMessageInspector() {

        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="isBidirectional">是否支持双向消息头存储</param>
        public ClientMessageInspector(bool isBidirectional, PolicyLevel policyLevel) {
            IsBidirectional = isBidirectional;
            this.PolicyLevel = policyLevel;
        }

        void IClientMessageInspector.AfterReceiveReply(ref System.ServiceModel.Channels.Message reply,
            object correlationState) {
            OnReceive(ref reply);
        }

        private Exception GetException(FaultMessage exceptionDetail) {
            if (null == exceptionDetail.InnerException) {
                if (exceptionDetail.Type == "MySql.Data.MySqlClient.MySqlException")
                    throw new System.Exception(exceptionDetail.Message);
                return (Exception)Activator.CreateInstance(Type.GetType(exceptionDetail.AssemblyQualifiedName), exceptionDetail.Message);
            }

            Exception innerException = GetException(exceptionDetail.InnerException);
            return (Exception)Activator.CreateInstance(Type.GetType(exceptionDetail.AssemblyQualifiedName), exceptionDetail.Message, innerException);
        }

        object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request,
                    System.ServiceModel.IClientChannel channel) {
            OnSend(ref request);
            return null;
        }

        void OnSend(ref Message request) {
            if (IsBidirectional) {
                if (PolicyLevel != ServiceModel.PolicyLevel.None)
                    if (System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated)
                        new TokenProvider().CreateToken(Authorization.User, true);
                ApplicationContext.Current.CultureName = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
                MessageHeader<ApplicationContext> contextHeader = new MessageHeader<ApplicationContext>(ApplicationContext.Current);

                request.Headers.Add(contextHeader.GetUntypedHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace));

                Trace.TraceInformation("MessageInspector\tput application context data into client message header");
            }
        }

        void OnReceive(ref Message reply) {
            if (IsBidirectional && reply.Headers.FindHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace) > -1) {
                ApplicationContext context = reply.Headers.GetHeader<ApplicationContext>(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace);
                if (context != null)
                    ApplicationContext.Current = context;
                else
                    Trace.TraceWarning("MessageInspector\tcan not find application context from service message header");
            }

            if (reply.IsFault && reply.Headers.Action == FaultMessage.FaultAction) {
                MessageFault fault = MessageFault.CreateFault(reply, int.MaxValue);
                if (fault.Code.SubCode.Name == FaultMessage.FaultSubCodeName &&
                    fault.Code.SubCode.Namespace == FaultMessage.FaultSubCodeNamespace) {
                    FaultException<FaultMessage> exception = (FaultException<FaultMessage>)FaultException.CreateFault(fault, typeof(FaultMessage));
                    Trace.TraceWarning("MessageInspector\tservice post a exception:" + exception.Detail);
                    throw GetException(exception.Detail);
                }
            }
        }

        
    }

 

}
